<?php

class Model{
	
	protected $_tableName;
	protected $_isLoggable = false;
	
	private $conn;
	private $logger;
	
	public function __construct($tableName = null) {
		if( $tableName != null )
			$this->_tableName = $tableName;
		if( $this->_isLoggable ) 
			$this->logger = Logger::createInstance($this->_tableName);
		return $this;
	}

    private function isValid($var){
    	return ( $var != "" && $var != null );
    }
    
	private function anti_injection($value){
		$value = preg_replace("/(from|select|insert|delete|where|drop table|show tables|#|\\*|--|\\\\)/", "" ,$value);
		$value = trim($value);
		$value = strip_tags($value);
		$value = (get_magic_quotes_gpc()) ? $value : addslashes($value);
		return $value;
	}
    
    private function executeQuery($sql) {
    	$this->conn = Conection::open();
    	$rs = mysql_query( $sql, $this->conn );
    	return ($rs != null) ? $rs : false ;
    }
	    
    private function serialize($arr,$type,$boolSeparator,$boolUnlike = true) {
    	
    	if( $type != "us" && $type != "i" )
    		return false;
    	
    	$bool = ( $type == "us" ) ? $boolSeparator : true ;
    	$s = ( $bool ) ? ", " : " AND " ;
    	
    	$keys = "";
    	$values = "";
    	$camps = "";
    	
    	$i = 0;
    	
		foreach ($arr as $key => $value){
			
			$key = Util::decamelize($key);
				
			//echo $key.": ".$value."<br />";
			
			if( $type == "us" ){
				
				if( $i != 0 ){
					$camps .= $s;
				}
				
				$camps .= $key;
				$camps .= ( $boolUnlike )? "='" : " LIKE '%";
				$camps .= $this->anti_injection($value);
				$camps .= ( $boolUnlike )? "'": "%'";
			
			}else if ( $type == "i" ){
				
				if( $i != 0 ){
					$keys .= $s;
					$values .= $s;
				}
				
				$keys .= strtolower(substr($key,0,1)).substr($key,1);
				$values .= "'".$this->anti_injection($value)."'";
				
			}
			
			$i++;
			
		}
		
		return ( $type == "us" ) ? $camps : "(".$keys.") VALUES (".$values.")";
    }

    private function insertSQL(&$arr,$debug=false) {
    	$sql = "INSERT INTO ".$this->_tableName." ".$this->serialize(&$arr,"i",null);
    	if( $debug )
    		echo $sql;
		return $sql;
    }
    
    private function updateSQL(&$arr,$debug=false) {
    	$sql = "UPDATE ".$this->_tableName." SET ".$this->serialize(&$arr,"us",true)." WHERE id='".$arr['id']."'";
    	if ( $debug )
    		echo $sql;
    	return $sql;
    }
    
    private function deleteSQL($id) {
    	return "DELETE FROM ".$this->_tableName." WHERE id='".$id."'";
    }
    
    private function selectSQL(&$arr,$boolUnlike) {
    	return "SELECT * FROM ".$this->_tableName." WHERE ".$this->serialize(&$arr,"us",false,$boolUnlike);
    }
    
    // Para subclasses
	
	protected function selectWhere($string) {
		$sql = "SELECT * FROM ".$this->_tableName." WHERE ".$string;
		$rs = $this->executeQuery( $sql );
		$mat = array();
		while ( ($tmp = mysql_fetch_assoc($rs)) != null)
			$mat[] = $tmp;
		return $mat;
	}
    
    // Ações
    
	public function persist($arr,$debug=false){
		if( !self::isManaged(&$arr) ){
			$sql = $this->insertSQL($arr, $debug);
			$rs = $this->executeQuery( $sql );
    		if( $this->_isLoggable ) 
				$this->logger->log("insert", $sql);
			$arr['id'] = mysql_insert_id($this->conn);
		}else {
			$arr = $this->merge($arr, $debug ); 
		}
		return $arr;
	}
	
	public function merge($arr,$debug=false){
		if( self::isManaged(&$arr) ){
			$sql = $this->updateSQL($arr, $debug);
			$rs = $this->executeQuery( $sql );
    		if( $this->_isLoggable ) 
				$this->logger->log("update", $sql);
			return $this->findById( $arr['id'] );
		}
		return false;
	}
	
	public function save($arr,$debug=false){
		return $this->persist($arr, $debug);
	}
    
	public function delete($id,$really=false) {
		$obj = $this->findById($id);
		$sql = ( !$really ) ? "UPDATE ".$this->_tableName." SET ativo='0' WHERE id='".$id."'" : "DELETE FROM ".$this->_tableName." WHERE id='".$id."'";
		$rs = $this->executeQuery( $sql );
    	if( $this->_isLoggable ) 
			$this->logger->log("delete-".$really, $sql);
		return (mysql_affected_rows($this->conn) == 1) ? $obj : null;
	}
	
	public function findById($id){
		$sql = "SELECT * FROM ".$this->_tableName." WHERE id='".$id."'";
		$rs = $this->executeQuery( $sql );
		$arr = mysql_fetch_assoc($rs);
		return $arr;
	}
	
	public function find($arr,$boolUnlike=true){
		$sql = $this->selectSQL(&$arr,&$boolUnlike);
		$rs = $this->executeQuery( $sql );
		$mat = array();
		while ( ($tmp = mysql_fetch_assoc($rs)) != null)
			$mat[] = $tmp;
		return $mat;
	}
	
	public function findOne($arr,$boolUnlike=true){
		$sql = $this->selectSQL(&$arr,&$boolUnlike)." LIMIT 0,1";
		$rs = $this->executeQuery( $sql );
		$arr = mysql_fetch_assoc($rs);
		return $arr;
	}
	
	public function findAndOrderBy($arr,$camp,$asc=true,$boolUnlike=true){
		$sql = $this->selectSQL(&$arr,&$boolUnlike);
		$rs = $this->executeQuery( $sql." ORDER BY ".$camp ." ".( $asc ? "ASC" : "DESC" ) );
		$mat = array();
		while ( ($tmp = mysql_fetch_assoc($rs)) != null)
			$mat[] = $tmp;
		return $mat;
	}
	
	public function findAll($ativo=null){
		$sql = "SELECT * FROM ".$this->_tableName;
		if( $ativo != null ){
			$sql .= " WHERE ativo=".$ativo;
		}
		$rs = $this->executeQuery( $sql );
		$mat = array();
		while ( ($tmp = mysql_fetch_assoc($rs)) != null)
			$mat[] = $tmp;
		return $mat;
	}

	// Ações estáticas
	
    public static function executeSQL($sql) {
    	$conn = Conection::open();
    	$rs = mysql_query( $sql, $conn );
    	return ($rs != null) ? $rs : false ;
    }
    
    public static function isManaged($arr){
    	if( is_array($arr) ){
    		if( array_key_exists("id", $arr) ){
    			if( is_numeric( $arr['id'] ) )
    				return true;
    			unset( $arr['id'] );
    		}
    	}
    	return false;
    }

}

?>